/*
 * Copyright 2009 rashaguo <rashaguo@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include "logger.h"

#include <QMutexLocker>
#include <QMutex>
#include <QTime>
#include <QDate>

#include <iostream>
#include <stdio.h>
#include <sstream>
#include <stdarg.h>

#ifdef _MSC_VER
 #define vsnprintf _vsnprintf
#endif

QMutex Logger::m_mutex;

Logger::Helper::Helper(const char* component, Level level, const char *className, const char* fileName, int line)
:m_component(component), m_level(level), m_className(className), m_fileName(fileName),m_line(line)
{
}

void Logger::Helper::operator()(const std::string &message)
{
    Logger::getInstance()->log(m_component, m_level, m_className, message, m_fileName, m_line);
}

void Logger::Helper::operator()(const char* format, ...)
{
    char buffer[1024];
    va_list ap;
    va_start(ap, format);
    vsnprintf(buffer, sizeof(buffer), format, ap);
    va_end(ap);
    Logger::getInstance()->log(m_component, m_level, m_className, buffer, m_fileName, m_line);
}

Logger::Logger()
{
    m_logFileState = LogFileState_Unset;
}

Logger* Logger::getInstance()
{
    static Logger instance;
    return &instance;
}

Logger::~Logger()
{
    flush();
    m_file.close();
}

void Logger::setLogFileName(const std::string &name)
{
    if(name == "")
    {
        m_logFileState = LogFileState_Disabled;
    }
    else
    {
        m_logFileState = LogFileState_Defined;
        m_logFileName = name;
    }
}

std::string Logger::getLogFileName() const
{
    return m_logFileName;
}

void Logger::debug(const std::string &component, const std::string &className, const std::string &message)
{
    log(component, Debug, className, message);
}

void Logger::info(const std::string &component, const std::string &className, const std::string &message)
{
    log(component, Info, className, message);
}

void Logger::warn(const std::string &component, const std::string &className, const std::string &message)
{
    log(component, Warn, className, message);
}

void Logger::error(const std::string &component, const std::string &className, const std::string &message)
{
    log(component, Error, className, message);
}

void Logger::fatal(const std::string &component, const std::string &className, const std::string &message, const char* fileName, int line)
{
    log(component, Fatal, className, message, fileName, line);
    flush();
}

Logger::Helper Logger::getHelper(const char* component, Logger::Level level , const char* className, const char* fileName, int line)
{
    return Logger::Helper(component, level, className, fileName, line);
}

void Logger::log(const std::string & component, Level level, const std::string &className,
                    const std::string & message, const char * fileName, int line)
{
    QMutexLocker locker(&m_mutex);

    std::string levelStr;

    switch(level)
    {
        case Debug:
            levelStr = "debug";
            break;
        case Info:
            levelStr = "info";
            break;
        case Warn:
            levelStr = "warn";
            break;
        case Error:
            levelStr = "error";
            break;
        default:
            levelStr = "fatal";
            break;
    }
    std::string tmp = "(" + levelStr + ")" + QTime::currentTime().toString().toStdString() + "[" + component + "]";
    if(fileName)
    {
        tmp += " " +std::string(fileName) + ":" + QString::number(line).toStdString();
    }
    tmp += " " + className + ": " + message;

    if(m_logFileState == LogFileState_Unset)
    {
       // std::cerr
       return;
    }
    else if(m_logFileState == LogFileState_Defined)
    {
        m_file.open(m_logFileName.c_str());
        m_file << "Log file=" << m_logFileName << std::endl;
        m_file << "Date=" << QDate::currentDate().toString().toStdString() << std::endl;
        m_file << "Time=" << QTime::currentTime().toString().toStdString() <<std::endl << std::endl;
        m_logFileState = LogFileState_Created;

    }

    if(m_logFileState == LogFileState_Created)
    {
        m_file << tmp << std::endl;
    }
}

void Logger::flush()
{
    QMutexLocker locker(&m_mutex);

    m_file.flush();

}
